﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MetaWeblogHandler.cs" company="ecblog.codeplex.com">
//   emrecoskun.net - ibrahimatay.org
// </copyright>
// <summary>
//   Meta Weblog Handler
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace EcBlog.Api.MetaWeblog
{
    using System;
    using System.Collections.Generic;
    using System.Data.Objects.DataClasses;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Web;

    using CookComputing.XmlRpc;

    using EcBlog.Composition;
    using EcBlog.Data;
    using EcBlog.Extensions;
    using EcBlog.Models;

    using WebMatrix.WebData;

    /// <summary>
    /// Meta Weblog Handler
    /// </summary>
    public class MetaWeblogHandler : XmlRpcService, IMetaWeblog
    {
        private readonly IEcUnitOfWork unitOfWork; 

        /// <summary>
        /// Initializes a new instance of the <see cref="MetaWeblogHandler"/> class.
        /// </summary>
        public MetaWeblogHandler()
        {
            this.unitOfWork =
                CompositionDependencyResolver.StaticFactory.GetService(typeof(IEcUnitOfWork)) as IEcUnitOfWork;
        }

        /// <summary>
        /// Adds the post.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="post">The post.</param>
        /// <param name="publish">if set to <c>true</c> [publish].</param>
        /// <returns>
        /// The post id.
        /// </returns>
        public string AddPost(string blogid, string username, string password, Post post, bool publish)
        {
            this.LogIn(username, password);

            this.unitOfWork.PageRepository.Create(
                new Page
                    {
                        Created = DateTime.Now,
                        Published = publish ? DateTime.Now : DateTime.Now.AddDays(7),
                        IsPublish = publish,
                        LayoutId = 1,
                        Slug = string.IsNullOrEmpty(post.wp_slug) ? this.SelfUrl(post.title) : post.wp_slug,
                        ContentHtml = post.description,
                        LastModified = DateTime.Now,
                        Title = post.title,
                        Summary = post.excerpt,
                        IsCommentable = true,
                        ShowPostList = true,
                        Tags = this.GetTags(post.categories),
                    });
            this.unitOfWork.Save();
            return UrlHelpersExtensions.GetSlugUrl(null, DateTime.Now, string.IsNullOrEmpty(post.wp_slug) ? this.SelfUrl(post.title) : post.wp_slug);
        }

        /// <summary>
        /// Updates the post.
        /// </summary>
        /// <param name="postid">The postid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="post">The post.</param>
        /// <param name="publish">if set to <c>true</c> [publish].</param>
        /// <returns>
        ///   <c>true</c> if the post updated
        /// </returns>
        public bool UpdatePost(string postid, string username, string password, Post post, bool publish)
        {
            this.LogIn(username, password);
            var slug = Path.GetFileNameWithoutExtension(postid);
            var page = this.unitOfWork.PageRepository.Get().FirstOrDefault(x => x.Slug == slug);
            try
            {
                if (page == null)
                {
                    return false;
                }

                page.ContentHtml = post.description;
                page.Summary = post.excerpt;
                page.Slug = string.IsNullOrEmpty(post.wp_slug) ? this.SelfUrl(post.title) : post.wp_slug;
                page.Title = post.title;
                page.IsPublish = publish;
                page.LastModified = DateTime.Now;
                page.Tags = this.GetTags(post.categories);
                this.unitOfWork.PageRepository.Update(page);
                this.unitOfWork.Save();
                return true;
            }
            catch (Exception exception)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
                return false;
            }
        }

        /// <summary>
        /// Gets the post.
        /// </summary>
        /// <param name="postid">The postid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// The post.
        /// </returns>
        public Post? GetPost(string postid, string username, string password)
        {
            this.LogIn(username, password);
            var slug = Path.GetFileNameWithoutExtension(postid);
            var page = this.unitOfWork.PageRepository.Get().FirstOrDefault(x => x.Slug == slug);
            if (page != null)
            {
                var post = new Post
                    {
                        postid = postid,
                        title = page.Title,
                        categories = this.GetStringArrayToTag(page.Tags),
                        wp_slug = page.Slug,
                        description = page.ContentHtml,
                        excerpt = page.Summary,
                        userid = string.Empty
                    };
                return post;
            }

            return null;
        }

        /// <summary>
        /// Gets the categories.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// The category infos.
        /// </returns>
        public CategoryInfo[] GetCategories(string blogid, string username, string password)
        {
            this.LogIn(username, password);

            return this.unitOfWork.TagRepository.Get().ToList()
                .Select(categoryInfo =>
                        new CategoryInfo
                            {
                                description = string.Empty,
                                title = categoryInfo.TagName,
                                htmlUrl = categoryInfo.TagSlug,
                                rssUrl = string.Empty,
                                categoryid = categoryInfo.TagId.ToString(CultureInfo.InvariantCulture),
                            }).ToArray();
        }

        /// <summary>
        /// Gets the recent posts.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="numberOfPosts">The number of posts.</param>
        /// <returns>
        /// The posts.
        /// </returns>
        public Post[] GetRecentPosts(string blogid, string username, string password, int numberOfPosts)
        {
            this.LogIn(username, password);
            return this.unitOfWork.PageRepository.Get().Take(numberOfPosts).ToList()
                .Select(post =>
                        new Post
                            {
                                title = post.Title,
                                postid = post.PageId,
                                wp_slug = post.Slug,
                                description = post.ContentHtml,
                                excerpt = post.Summary,
                                dateCreated = post.Created,
                                commentPolicy = post.IsCommentable.ToString(CultureInfo.InvariantCulture),
                                categories = this.GetStringArrayToTag(post.Tags),
                                permalink = UrlHelpersExtensions.GetSlugUrl(null, post.Published, post.Slug, string.Empty),
                                userid = string.Empty,
                                source = new Source
                                             {
                                                 name = post.Title,
                                                 url = UrlHelpersExtensions.GetSlugUrl(null, post.Published, post.Slug, string.Empty)
                                             }
                            }).ToArray();
        }

        /// <summary>
        /// News the media object.
        /// </summary>
        /// <param name="blogid">The blogid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="mediaObject">The media object.</param>
        /// <returns>
        /// The media object info.
        /// </returns>
        public MediaObjectInfo NewMediaObject(string blogid, string username, string password, MediaObject mediaObject)
        {
            this.LogIn(username, password);
            var filename = Path.GetFileName(mediaObject.name);
            var filepath = string.Format("/Content/UserFiles/{0}/", Path.GetDirectoryName(mediaObject.name));

            // var virtualpath = string.Format("{0}/image.axd?picture=/{1}", this._settingRepository[SiteSettingKey.SiteUrl], mediaObject.name);
            var virtualpath = string.Format("/Content/UserFiles/{0}", mediaObject.name);
            try
            {
                var serverpath = HttpContext.Current.Server.MapPath(filepath);
                if (!Directory.Exists(serverpath))
                {
                    Directory.CreateDirectory(serverpath);
                }

                if (filename != null)
                {
                    File.WriteAllBytes(HttpContext.Current.Server.MapPath(filepath + filename), mediaObject.bits);
                }
            }
            catch (Exception exception)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
            }

            return new MediaObjectInfo { url = virtualpath };
        }

        /// <summary>
        /// Deletes the post.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="postid">The postid.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <param name="publish">if set to <c>true</c> [publish].</param>
        /// <returns>
        /// If post deleted <c>true</c>
        /// </returns>
        public bool DeletePost(string key, string postid, string username, string password, bool publish)
        {
            try
            {
                this.LogIn(username, password);
                var slug = Path.GetFileNameWithoutExtension(postid);
                var page = this.unitOfWork.PageRepository.Get().FirstOrDefault(x => x.Slug == slug);
                if (page != null)
                {
                    this.unitOfWork.PageRepository.Delete(page.PageId);
                    this.unitOfWork.Save();
                    return true;
                }

                return false;
            }
            catch (Exception exception)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
                return false;
            }
        }

        /// <summary>
        /// Gets the users blogs.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// The blog infos.
        /// </returns>
        public BlogInfo[] GetUsersBlogs(string key, string username, string password)
        {
            this.LogIn(username, password);
            var blogInfos =
                new List<BlogInfo>
                    {
                        new BlogInfo
                            {
                                blogName = this.unitOfWork.SiteSettingRepository[SiteSettingKey.SiteTitle],
                                blogid = this.unitOfWork.SiteSettingRepository[SiteSettingKey.BlogRpcId],
                                url = this.unitOfWork.SiteSettingRepository[SiteSettingKey.SiteUrl]
                            }
                    };
            return blogInfos.ToArray();
        }

        /// <summary>
        /// Gets the user info.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// The user info.
        /// </returns>
        public UserInfo GetUserInfo(string key, string username, string password)
        {
            this.LogIn(username, password);
            return new UserInfo
                {
                    firstname = this.unitOfWork.SiteSettingRepository[SiteSettingKey.Author],
                    email = this.unitOfWork.SiteSettingRepository[SiteSettingKey.CommentAlertEMail],
                    nickname = this.unitOfWork.SiteSettingRepository[SiteSettingKey.SiteSlogan],
                    userid = this.unitOfWork.SiteSettingRepository[SiteSettingKey.BlogRpcId]
                };
        } 

        /// <summary>
        /// Selfs the URL.
        /// </summary>
        /// <param name="word">The word.</param>
        /// <returns>the URL</returns>
        public string SelfUrl(string word)
        {
            word = word.ToLower();
            word = word.Trim('-');
            word = word.ToLower();
            word = word.Replace("ü", "u");
            word = word.Replace("ğ", "g");
            word = word.Replace("ö", "o");
            word = word.Replace("ş", "s");
            word = word.Replace("ç", "c");
            word = word.Replace("ı", "i");
            word = word.Replace("!", string.Empty);
            word = word.Replace("?", string.Empty);
            word = word.Replace(".", string.Empty);
            word = word.Replace("!", string.Empty);
            word = word.Replace("'", "-");
            word = word.Replace("#", "sharp");
            word = word.Replace(";", string.Empty);
            word = word.Replace(")", string.Empty);
            word = word.Replace("[", string.Empty);
            word = word.Replace("]", string.Empty);
            word = word.Replace("(", string.Empty);
            word = word.Replace(" ", "-");
            word = word.Replace("--", "-");
            word = word.Replace("---", "-");
            word = word.Replace("----", "-");
            return word.Trim();
        }

        /// <summary>
        /// Gets the tags.
        /// </summary>
        /// <param name="tags">The tags.</param>
        /// <returns>The tag entity collection.</returns>
        public EntityCollection<Tag> GetTags(string[] tags)
        {
            var tagcollection = new EntityCollection<Tag>();

            foreach (var s in tags)
            {
                string s1 = s;
                var t = this.unitOfWork.TagRepository.Get().FirstOrDefault(x => x.TagName == s1);
                if (t == null)
                {
                    tagcollection.Add(new Tag
                        {
                            TagName = s,
                            TagSlug = this.SelfUrl(s),
                        });
                }
                else
                {
                    tagcollection.Add(t);
                }
            }

            return tagcollection;
        }

        /// <summary>
        /// Gets the string array to tag.
        /// </summary>
        /// <param name="tags">The tags.</param>
        /// <returns>The tag array.</returns>
        public string[] GetStringArrayToTag(ICollection<Tag> tags)
        {
            return tags == null ? new string[] { } : tags.Select(t => t.TagName).ToArray();
        }

        private void LogIn(string username, string password)
        {
            if (!WebSecurity.Login(username, password, persistCookie: true))
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(
                    new Exception(
                        string.Format("User authentication failed - {0}", HttpContext.Current.Request.UserHostName)));
                throw new MetaWeblogException("User authentication failed");
            }
        }
    }
}